#include "iniFile.h"
#include <sstream>
#include <fstream>
#include <iostream>

using namespace utility::common;
using namespace utility::ini;

IniFile::IniFile()
{
}

IniFile::IniFile(const string& filename)
{
    load(filename);
}

bool IniFile::load(const string &filename)
{
    m_filename=filename;
    //open ini file
    ifstream fin(filename);
    if (fin.fail())
    {
        std::cout<<("loading file failed: %s is not found.\n", m_filename.c_str());
        throw std::logic_error("ini file not found");
        return false;
    }

    //逐行读取
    string line;
    string section;
    while (std::getline(fin, line))
    {
        line = trim(line);
        //跳过空行
        if (line.empty())
        {
            continue;
        }

        if (line[0] == '[') // it is a section
        {
            int pos = line.find_first_of(']');
            if(-1 != pos)
            {
                section = line.substr(1, pos - 1);
                section = trim(section);
                m_sections[section] = Section();
            }
        }
        else if('#' == line[0])  // it's a comment
        {
            continue;
        }
        else
        {
            int pos = line.find_first_of('=');
            string key = line.substr(0, pos);
            string value = line.substr(pos + 1, line.length() - pos);
            key = trim(key);
            value = trim(value);

            //if section already exist
            auto it = m_sections.find(section);
            if(it==m_sections.end())
            {
                printf("parsing error: section=%s key=%s\n", section.c_str(), key.c_str());
                return false;
            }
            m_sections[section][key] = value;
        }
    }
    fin.close();

    return true;
}

string IniFile::trim(string s)
{
    if (s.empty())
    {
        return s;
    }
    s.erase(0, s.find_first_not_of(" \r\n"));
    s.erase(s.find_last_not_of(" \r\n") + 1);
    return s;
}

Value & IniFile::get(const string & section, const string & key)
{
    return m_sections[section][key];
}

void IniFile::set(const string &section, const string &key, const Value &value)
{
    m_sections[section][key] = value;
}

bool IniFile::has(const string &section,const string & key)
{
    std::map<string, Section>::const_iterator it =m_sections.find(section);
    if(it != m_sections.end())
    {
        return (it->second.find(key) != it->second.end());
    }
    return false;
}

bool IniFile::has(const string &section)
{
    return m_sections.find(section) != m_sections.end();
}

void IniFile::remove(const string &section, const string &key)
{
    std::map<string, Section>::iterator it = m_sections.find(section);
    if(it != m_sections.end())
    {
        it->second.erase(key);
    }
}

void IniFile::remove(const string &section)
{
    m_sections.erase(section);
}

void IniFile::clear()
{
    m_sections.clear();
}

string IniFile::str()
{
    stringstream ss;
    std::map<string, Section>::iterator it = m_sections.begin();
    for(; it!= m_sections.end(); ++ it)
    {
        ss << "[" << it->first << "]" <<std::endl;
        std::map<string,Value>::iterator iter= it->second.begin();
        for(; iter != it->second.end(); ++iter)
        {
            ss << iter->first << " = " << string(iter->second) <<std::endl;
        }
        ss << std::endl;
    }

    return ss.str();

} 


void IniFile::show()
{    
    std::cout << str();
}

bool IniFile::save(const string & filename)
{
    ofstream fout(filename);
    if(fout.fail())
    {
        return false;
    }

    fout << str();
    fout.close();
    return true;
}